#ifndef BOSS_Afterburner_ListedObject_H
#define BOSS_Afterburner_ListedObject_H

#include <list>
#include <string>

/// @addtogroup Afterburner_objects
/// @{

/// Derive from this base object using the [Curiously Recurring Template Pattern
/// (CRTP)](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) and all instances of
/// the derived object will be keep tracked of in a list unique to that class.
/// @author   Remco de Boer 雷穆克 (r.e.deboer@students.uu.nl or remco.de.boer@ihep.ac.cn)
/// @date     April 14th, 2019
template <class T>
class ListedObject
{
public:
  ListedObject() { fInstances.push_back(this); }
  ~ListedObject() { fInstances.remove(this); }

  static const Ssiz_t GetNInstances() { return fInstances.size(); }

  static void       IterReset() { fIterator = fInstances.begin(); }
  static const bool IterIsEnd() { return fIterator == fInstances.end(); };
  static T*         IterNext();
  static T*         IterGetObject();

private:
  static typename std::list<const ListedObject<T>*>           fInstances;
  static typename std::list<const ListedObject<T>*>::iterator fIterator;
};

/// @}

template <class T>
typename std::list<const ListedObject<T>*> ListedObject<T>::fInstances;
template <class T>
typename std::list<const ListedObject<T>*>::iterator ListedObject<T>::fIterator{fInstances.end()};

template <class T>
T* ListedObject<T>::IterNext()
{
  if(IterIsEnd()) return nullptr;
  ++fIterator;
  return IterGetObject();
}

template <class T>
T* ListedObject<T>::IterGetObject()
{
  if(IterIsEnd()) return nullptr;
  return (T*)*fIterator;
}

#endif